package com.im.service.interceptor;

import com.alibaba.fastjson.JSONObject;;
import com.im.service.config.AppConfig;
import com.im.common.constant.Constants;
import com.im.common.enums.exception.BaseErrorCode;
import com.im.common.enums.exception.GateWayErrorCode;
import com.im.common.enums.ImUserTypeEnum;
import com.im.common.enums.exception.BaseExceptionEnum;
import com.im.common.utils.SigAPI;
import com.im.service.user.entity.ImUserDataEntity;
import com.im.service.user.service.ImUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 用户身份验证类
 */
@Slf4j
@Component
public class IdentityCheck {

    @Autowired
    private ImUserService imUserService;
    @Autowired
    private AppConfig appConfig;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 检查用户鉴权票据
     *
     * @param identifier 用户ID
     * @param appId      应用ID
     * @param userSig    鉴权票据
     * @return 检查结果
     */
    public BaseExceptionEnum checkUserSig(String identifier, String appId, String userSig) {
        // 从Redis中获取缓存的鉴权票据
        String cacheUserSig = stringRedisTemplate.opsForValue().get(appId + ":" + Constants.RedisConstants.userSign + ":" + identifier + userSig);
        if (!StringUtils.isBlank(cacheUserSig) && Long.valueOf(cacheUserSig) > System.currentTimeMillis() / 1000) {
            // 如果缓存中存在且未过期，则设置用户为管理员身份，并返回成功
            this.setIsAdmin(identifier, Integer.valueOf(appId));
            return BaseErrorCode.SUCCESS;
        }

        // 获取秘钥
        String privateKey = appConfig.getPrivateKey();

        // 根据appid + 秘钥创建sigApi
        SigAPI sigAPI = new SigAPI(Long.valueOf(appId), privateKey);

        // 调用sigApi对userSig解密
        JSONObject jsonObject = sigAPI.decodeUserSig(userSig);

        //取出解密后的appid 和 操作人 和 过期时间做匹配，不通过则提示错误
        Long expireTime = 0L;
        Long expireSec = 0L;
        Long time = 0L;
        String decoerAppId = "";
        String decoderidentifier = "";

        try {
            decoerAppId = jsonObject.getString("TLS.appId");
            decoderidentifier = jsonObject.getString("TLS.identifier");
            String expireStr = jsonObject.get("TLS.expire").toString();
            String expireTimeStr = jsonObject.get("TLS.expireTime").toString();
            time = Long.valueOf(expireTimeStr);
            expireSec = Long.valueOf(expireStr);
            expireTime = Long.valueOf(expireTimeStr) + expireSec;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("checkUserSig-error:{}", e.getMessage());
        }

        if (!decoderidentifier.equals(identifier)) {
            // 操作人不匹配，返回错误
            return GateWayErrorCode.USERSIGN_OPERATE_NOT_MATE;
        }

        if (!decoerAppId.equals(appId)) {
            // appid不匹配，返回错误
            return GateWayErrorCode.USERSIGN_IS_ERROR;
        }

        if (expireSec == 0L) {
            // 过期时间为0，返回错误
            return GateWayErrorCode.USERSIGN_IS_EXPIRED;
        }

        if (expireTime < System.currentTimeMillis() / 1000) {
            // 鉴权票据已过期，返回错误
            return GateWayErrorCode.USERSIGN_IS_EXPIRED;
        }

        // appid + "xxx" + userId + sign
        String genSig = sigAPI.genUserSig(identifier, expireSec, time, null);
        if (genSig.toLowerCase().equals(userSig.toLowerCase())) {
            // 生成的鉴权票据与传入的鉴权票据匹配，缓存鉴权票据并设置用户为管理员身份，并返回成功
            String key = appId + ":" + Constants.RedisConstants.userSign + ":" + identifier + userSig;
            Long etime = expireTime - System.currentTimeMillis() / 1000;
            stringRedisTemplate.opsForValue().set(key, expireTime.toString(), etime, TimeUnit.SECONDS);
            this.setIsAdmin(identifier, Integer.valueOf(appId));
            return BaseErrorCode.SUCCESS;
        }
        // 鉴权票据不匹配，返回错误
        return GateWayErrorCode.USERSIGN_IS_ERROR;
    }


    /**
     * 根据appid,identifier判断是否App管理员,并设置到RequestHolder
     *
     * @param identifier 用户ID
     * @param appId      应用ID
     */
    public void setIsAdmin(String identifier, Integer appId) {
        // 去DB或Redis中查找用户信息，判断用户是否为管理员，并设置到RequestHolder中
        ImUserDataEntity singleUserInfo = imUserService.getSingleUserInfo(identifier, appId);
        if (singleUserInfo != null) {
            RequestHolder.set(singleUserInfo.getUserType() == ImUserTypeEnum.APP_ADMIN.getCode());
        } else {
            RequestHolder.set(false);
        }
    }
}
